package cn.zjutleo.village_server.aspect;

import cn.hutool.core.util.StrUtil;
import cn.zjutleo.village_server.annotation.OperationLog;
import cn.zjutleo.village_server.annotation.RequiresLogin;
import cn.zjutleo.village_server.config.UserOperationLogConfig;
import cn.zjutleo.village_server.util.IpUtil;
import cn.zjutleo.village_server.util.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * @author : Qin Zhenghan
 * @date : Created in 2021/8/14
 * @description: 自定义行为日志注解切面实现类
 */
@Slf4j
@Aspect
@Component
public class OperationLogAspect {
    @Resource
    private UserOperationLogConfig userOperationLogConfig;

    @Pointcut("@annotation(cn.zjutleo.village_server.annotation.OperationLog)")
    public void execute() {

    }

    @Before("execute()")
    public void recordLog(JoinPoint joinPoint) {
        OperationLog operationLog = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(OperationLog.class);
        ServletRequestAttributes attribute = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        // 获取当前操作用户id
        Integer currentUser = -1;
        if (method.isAnnotationPresent(RequiresLogin.class)) {
            currentUser = ThreadLocalUtil.getCurrentUser();
        }

        // 获取当前操作用户IP
        String currentIp = "unknown";
        if (attribute != null) {
            currentIp = IpUtil.getIpAddr(attribute.getRequest());
        }

        log.info(userOperationLogConfig.getFormat(),
                operationLog.module(),
                operationLog.method(),
                operationLog.ignoreParameters() ? "" : formatParameters(joinPoint.getArgs(), method.getParameters()),
                StrUtil.format("userId={} IP={}", currentUser, currentIp)
        );
    }

    private String formatParameters(Object[] args, Parameter[] parameters) {
        StringBuilder sb = new StringBuilder();
        int len = parameters.length;

        for (int i = 0; i < len; i++) {
            sb.append(StrUtil.format("{}={} ", parameters[i].getName(), String.valueOf(args[i])));
        }
        return sb.toString();
    }
}